package paper.cluster;

import java.sql.*;

import java.io.PrintWriter;
import java.io.FileWriter;
import java.io.IOException;

import java.util.HashSet;
import java.util.HashMap;
import java.util.Date;
import java.util.Random;
import java.util.Iterator;
import java.util.Vector;

import paper.db.DB;
import paper.db.Paper;
import paper.db.PaperIndex;

import paper.graph.Matrix;
import paper.graph.PaperGraph;
import paper.graph.Vertex;


public class GenMatrices 
{
    static public Matrix makeDistanceMatrix(HashSet<Paper> x)
    {
        // A flat (ie indexed) array of papers
        Paper[] flat = new Paper[ x.size() ];
        int i=0;
        for(Iterator<Paper> j = x.iterator(); j.hasNext(); )
            flat[i++] = j.next();

/*        // Using a map to turn a reference into an index
        HashMap<Paper,Integer> lookup = new HashMap<Paper,Integer>();
        for(i=0; i<x.size(); i++)
            lookup.put(flat[i],i);
*/
        Matrix adj = new Matrix( x.size(), x.size() );
        for(i=0; i<x.size(); i++)
        {
            for(int j=0; j<x.size(); j++)
            {
                if( i==j )
                    adj.set(i,j,0);
                else
                {
                    HashSet<String> auth = new HashSet<String>(flat[i].canonAuthors);
                    auth.retainAll( flat[j].canonAuthors );
                    if( auth.size() > 0 )
                        adj.set(i,j,1);
                    else
                        adj.set(i,j,Matrix.BIG);
                }
            }
        }
        Matrix m = new Matrix( x.size(), x.size() );
        for(i=0; i<x.size(); i++)
        {
            for( int j=0; j<x.size(); j++)
            {   
                if( i==j )
                    m.set(i,j,0);
                else
                    m.set(i,j,Matrix.BIG);
            }
        }
        for(i=0; i<10; i++)
            m.multiply(adj);
        int counts[] = new int[10];
        for(i=0; i<x.size(); i++)
            for(int j=0; j<x.size(); j++)
                if( m.get(i,j) < 10)
                    counts[ (int)m.get(i,j) ]++;
        for(i=0;i<10;i++)
            System.out.println(counts[i]);
        
        return m;
    }
        

    static public void makeBiCoauthor(PrintWriter out, HashSet<Paper> x) throws IOException
    {
        HashSet<String> allAuthors = new HashSet<String>();
        for(Iterator<Paper> i=x.iterator(); i.hasNext(); )
        {
            Paper p = i.next();
            allAuthors.addAll( p.canonAuthors );
        }
        out.println("authors = {");
        for(Iterator<String> i=allAuthors.iterator(); i.hasNext(); )
        {
            String name = i.next();
            out.println("'"+name+"';");
        }
        out.println("}");
        out.println("papers = {");
        for(Iterator<Paper> i=x.iterator(); i.hasNext(); )
        {
            Paper p = i.next();
            String tit = p.title.replace('\'',' ').replace('\n',' ');
            out.println("'"+tit+"';");
        }
        out.println("}");
    
        out.println("cspubs = [");
        for(Iterator<Paper> i=x.iterator(); i.hasNext(); )
        {
            Paper row = i.next();
            for(Iterator<String> j=allAuthors.iterator(); j.hasNext(); )
            {
                String name = j.next();
                if( row.canonAuthors.contains(name) )
                    out.print("1 ");
                else
                    out.print("0 ");
            }
            out.println(";");
        }
        out.println("];");
    }

    static public void makeCoauthor(PrintWriter out,HashSet<Paper> x) throws IOException
    {
        out.println("cspubs = [");
        for(Iterator<Paper> i=x.iterator(); i.hasNext(); )
        {
            Paper row = i.next();
            for(Iterator<Paper> j=x.iterator(); j.hasNext(); )
            {
                Paper col = j.next();
                HashSet<String> cp = new HashSet<String>(row.canonAuthors);
                cp.retainAll( col.canonAuthors );
                if( cp.size() > 0 )
                    out.print("1 ");
                else
                    out.print("0 ");
            }
            out.println(";");
        }
        out.println("];");
    }

    static public void makeCoauthorDiff(PrintWriter out,HashSet<Paper> x) throws IOException
    {
        out.println("cspubs = [");
        for(Iterator<Paper> i=x.iterator(); i.hasNext(); )
        {
            Paper row = i.next();
            for(Iterator<Paper> j=x.iterator(); j.hasNext(); )
            {
                Paper col = j.next();
                HashSet<String> cp = new HashSet<String>(row.canonAuthors);
                cp.retainAll( col.canonAuthors );
                int iSize = cp.size();
                cp.addAll(row.canonAuthors); 
                cp.addAll(col.canonAuthors); 
                int uSize = cp.size();
                double diff = 1.0 - (double)iSize / (double)uSize;
                out.print(diff + " ");
            }
            out.println(";");
        }
        out.println("];");
    }

    enum Source{ Undefined, Load, UniformRand, PowRand };
    enum Dest{ Undefined, Dot, Matlab };
    enum Alg{ None, MinLoops };

    public static void main(String[] args) throws IOException
    {
        Source src=Source.Undefined;
        Dest  dest=Dest.Undefined;
        Alg    alg=Alg.None;
        PaperIndex cache = new PaperIndex();
        PaperGraph<CEdge,Vertex> g;
        Matrix m;
        String filter = "xx.zip";
        String basename = "out";
        int size=10;
        for(int i=0; i<args.length; i++) {
            if( args[i].substring(0,2).equals("-f") )
                filter = args[i].substring(2);
            else if( args[i].substring(0,2).equals("-u") )
            {
                try {
                    size = Integer.parseInt( args[i].substring(2) );
                } catch(NumberFormatException e) {} 
                src = Source.UniformRand;
            }
            else if( args[i].substring(0,2).equals("-p") )
            {
                try {
                    size = Integer.parseInt( args[i].substring(2) );
                } catch(NumberFormatException e) {} 
                src = Source.PowRand;
            }
            else if( args[i].substring(0,2).equals("-l") )
                src = Source.Load;
            else if( args[i].substring(0,2).equals("-m") )
                dest = Dest.Matlab;
            else if( args[i].substring(0,2).equals("-d") )
                dest = Dest.Dot;
            else if( args[i].substring(0,2).equals("-o") )
                basename = args[i].substring(2);
            else if( args[i].substring(0,2).equals("-e") )
                alg = Alg.MinLoops;
        }
        switch( src )
        {
            default:
            case Undefined:
                System.out.println("Please set a graph source:");
                System.out.println(" -u<size> = Uniform random matrix");
                System.out.println(" -p<size> = Power-law random matrix");
                System.out.println(" -l       = Load the paperBase");
                System.exit(-1);
            case Load:
                g = new PaperGraph(cache);
                CEdge x = new CEdge("x","x");
                System.out.println(x);
                g.fillCiteGraphs("1dfc3abf8adffd53", x, 3);
                break;
            case PowRand:
                m = new Matrix(size,size);
                m.randomiseP();
                m.fold();
                g = m.makeGraph( 
                      new Matrix.GraphBuilder<CEdge,Vertex>() {
                        public PaperGraph<CEdge,Vertex> makeGraph() {
                            return new PaperGraph<CEdge,Vertex>((PaperIndex)null);
                        }
                        public CEdge makeEdge(String a, String b) {
                            return new CEdge(a,b);
                        }
                      } );
                break;
            case UniformRand:
                m = new Matrix(size,size);
                m.randomiseU();
                m.fold();
                g = m.makeGraph( 
                      new Matrix.GraphBuilder<CEdge,Vertex>() {
                        public PaperGraph<CEdge,Vertex> makeGraph() {
                            return new PaperGraph<CEdge,Vertex>((PaperIndex)null);
                        }
                        public CEdge makeEdge(String a, String b) {
                            return new CEdge(a,b);
                        }
                      } );
                break;
        }
        switch( alg )
        {
            case None:
                break;
            case MinLoops:
                PrintWriter prog = new PrintWriter( new FileWriter("progress.dot"));
                Cluster.minLoops(prog,g);
                prog.close();
                break;
        }
        switch( dest )
        {
            case Undefined:
                System.out.println("Please set a destination:");
                System.out.println(" -d  = Generate dot output to basename.dot");
                System.out.println(" -m  = Generate matlab output to basename.mat");
                System.out.println(" -o<base> = Change base of filename");
                return;
            case Dot:
                String filename = basename + ".dot";
                PrintWriter out = new PrintWriter( 
                                    new FileWriter(filename));
                g.dot(out,true,false);
                out.close();
                break;
            case Matlab:
        HashSet<Paper> x = Paper.loadUrlSet(filter,cache);

        Matrix dist = makeDistanceMatrix(x);
                break;
        }
                return;
/*
        PrintWriter out = new PrintWriter(new FileWriter( "bicoauth-pxa.mat" ));
        GenMatrices.makeBiCoauthor(out,x);
        out.close();

        out = new PrintWriter(new FileWriter( "coauth-pxp.mat" ));
        GenMatrices.makeCoauthor(out,x);
        out.close();

        out = new PrintWriter(new FileWriter( "coauth-diff-pxp.mat" ));
        GenMatrices.makeCoauthorDiff(out,x);
        out.close();
*/
    }
}

